﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls;
using Silvermoon.Shapes;
using Silvermoon.Images;
using Silvermoon.Windows.Styles;
using Silvermoon.OpenGL;
using Silvermoon.Windows;
using Silvermoon.UI;
using Silvermoon.Controls.Forms;
using Silvermoon.Controls.Base;

namespace Calculator
{
    /// <summary>
    /// Scientific calculator example.
    /// The layout depends on the orientation and for that case a Grid control is used with two different grid definitions.
    /// </summary>
    public class CalculatorPage : Page
    {
        private AnimationGrid grid;
        private GridDefinition landscapeGrid, portraitGrid;
        private Panel whitePanel1, whitePanel2;
        private TextBox textBox;
        private TextBox formulaBox;
        private CalcStateMachine stateMachine = new CalcStateMachine();

        public CalculatorPage()
            : base()
        {
            InitializePage();
        }

        protected override void Dispose(bool dispose)
        {
            base.Dispose(dispose);
        }


        private static readonly int[] redButtons = new int[] { 1, 16, 17, 18 };
        private static readonly int[] smallButtons = new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
        private static readonly int[] toggleButtons = new int[] { 9, 10 };

        private void InitializePage()
        {
            Title = "CALCULATOR";
            Styles = StylePool.Styles;

            SetTransition(400, TransitionMask.Bottom, TransitionMask.Bottom);

            CreateLandscapeGridDefinition();
            CreatePortraitGridDefinition();

            StackPanel sp = new StackPanel { Orientation = StackPanelOrientation.Vertical, Alignment = StackPanelAlignment.Dense, Margin = new Margin(5, 5, 5, null), Background = PhoneColors.White, Height = 48 + 64 };

            formulaBox = new TextBox { Margin = new Margin(0, 0, 0, null), Height = 48, ReadOnly = true, Alignment = Alignment.Far, TextColor = PhoneColors.MediumDark, Background = Shape.Empty };
            textBox = new TextBox { Margin = new Margin(0, 0, 0, null), Height = 64, ReadOnly = true, Text = "0", Alignment = Alignment.Far, Font = FontPool.MediumRegularFont, Background = Shape.Empty };
            sp.Controls.Add(formulaBox, textBox);

            grid = new AnimationGrid { Margin = new Margin(0, 48 + 64, 0, 0) };
            Controls.Add(grid, sp);
            grid.Definition = Orientation == Orientation.Landscape ? landscapeGrid : portraitGrid;
            int index = 1;

            whitePanel1 = new Panel { Background = PhoneColors.White, StyleName = "SpacePanel", Margin = Margin.Zero };
            whitePanel2 = new Panel { Background = PhoneColors.White, StyleName = "SpacePanel", Margin = Margin.Zero };
            grid.AddControl(0, whitePanel1);
            grid.AddControl(1, whitePanel2);

            ContextMenu cm = new ContextMenu { Behavior = AppearBehavior.OnTouchDown };
            cm.AddItem("standard");
            cm.AddItem("scientific").IsSelected = true;
            cm.AddItem("developer");
            cm.Showing += (s, e) => whitePanel2.Background = whitePanel1.Background = Shape.Empty;
            cm.Hidden += (s, e) => whitePanel2.Background = whitePanel1.Background = PhoneColors.White;

            foreach (Shape s in GetButtonShapes())
            {
                ButtonBase btn;
                if (toggleButtons.Contains(index))
                {
                    btn = new ToggleButton { Margin = Margin.Zero, OnContent = s, OffContent = s, StyleName = "CalcButton", AlwaysRaiseTapEvent = true };
                }
                else
                {
                    btn = new Button { Margin = Margin.Zero, Content = s, StyleName = "CalcButton" };
                }

                if (smallButtons.Contains(index)) { btn.TextColor = PhoneColors.Lime; btn.StyleName = "SmallButton"; }
                if (redButtons.Contains(index)) btn.TextColor = PhoneColors.Orange;

                if (index == 1)
                {
                    btn.ContextMenu = cm;
                    btn.StateManager = new VisualStateManager();
                }
                else
                {
                    btn.Tap += new EventHandler<TapEventArgs>(OnButtonTap);
                    btn.DoubleTap += new EventHandler<TapEventArgs>(OnButtonTap);
                }
                grid.AddControl(index + 1, btn);
                index++;
            }
        }

        void OnButtonTap(object sender, TapEventArgs e)
        {
            string token = GetTokenFromButton(sender as ButtonBase);
            stateMachine.AddToken(token);
            UpdateDisplay();
        }

        private void UpdateDisplay()
        {
            textBox.Text = stateMachine.Result;
            formulaBox.Text = stateMachine.Formula;
        }

        private string GetTokenFromButton(ButtonBase b)
        {
            Button btn = b as Button;
            if (btn != null)
            {
                StringShape ss = btn.Content as StringShape;
                return (ss != null) ? ss.Text : string.Empty;
            }
            else
            {
                ToggleButton t = b as ToggleButton;
                StringShape ss = t.OffContent as StringShape;
                return (ss != null) ? ss.Text : string.Empty;
            }
        }

        /// <summary>
        /// Creates the grid definition in portrait mode.
        /// </summary>
        private void CreatePortraitGridDefinition()
        {
            GridDefinition def = new GridDefinition();
            def.Rows.AddRange(20, 0.7f, 0.7f, 0.7f, 20, 1f, 1f, 1f, 1f, 1f, 11);
            def.Columns.AddRange(1f, 1f, 1f, 1f, 1f);
            def.CreateCell(0, 1, 5, 2);
            def.CreateCell(0, 5, 5, 5);

            int max = def.Rows.Count - 1;
            for (int r = 1; r < max; r++)
            {
                if (r == 4) continue;
                for (int c = 0; c < def.Columns.Count; c++)
                {
                    def.CreateCell(c, r);
                }
            }
            this.portraitGrid = def;
        }

        /// <summary>
        /// Creates the grid definition in landscape mode.
        /// </summary>
        private void CreateLandscapeGridDefinition()
        {
            GridDefinition def = new GridDefinition();
            def.Rows.AddRange(10, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f);
            def.Columns.AddRange(1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f);
            def.CreateCell(0, 1, 6, 8);
            def.CreateCell(6, 1, 2, 8);

            int[] defArray = new int[]{7,0, 7,6, 6,1, 6,2, 6,3, 6,4, 6,5, 6,6, 6,7, 7,7, 7,4, 7,5, 7,3, 7,1, 7,2,
                0,0, 0,2, 0,4, 0,6, 5,0, 1,0, 2,0, 3,0, 4,0, 6,0, 1,2, 2,2, 3,2, 4,2, 5,2, 1,4, 2,4, 3,4, 4,4, 5,4, 1,6, 2,6, 3,6, 4,6, 5,6};


            int max = (defArray.Length / 2);
            for (int i = 0; i < max; i++)
            {
                int c = defArray[i * 2];
                int r = defArray[i * 2 + 1] + 1;
                int rowSpan = c >= 6 ? 1 : 2;
                def.CreateCell(c, r, 1, rowSpan);
            }
            this.landscapeGrid = def;
        }

        public IEnumerable<Shape> GetButtonShapes()
        {
            return new Shape[] { 
                "mod","Pi","xY","x³","dgr",
                "sin","cos","tan","inv","hyp",
                "log","ln","eX","(",")",
                SysImages.Back, "CE", "C", "±", "√", 
                "7", "8", "9", "÷", "x²", 
                "4", "5", "6", "*", "1/x", 
                "1", "2", "3", "-", "!", 
                "0", ".", "=", "+" ,"E"};

        }

        public override void OnExitApplication()
        {
            Screen.Close();
        }

        protected override void OnOrientationChanged(object sender, EventArgs e)
        {
            if (grid != null)
            {
                grid.Definition = Orientation == Orientation.Landscape ? landscapeGrid : portraitGrid;
            }
            base.OnOrientationChanged(sender, e);
        }
    }
}
